package com.atguigu.ssyx.config;

import com.atguigu.ssyx.api.ZhgjApi;
import com.atguigu.ssyx.model.WebSocketResult;
import com.atguigu.ssyx.model.ZhgjResponse;
import com.atguigu.ssyx.service.OpenGateService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@Component
@Slf4j
public class WebSocketHandler extends TextWebSocketHandler {

    @Autowired
    private ZhgjApi zhgjApi;
    @Autowired
    private OpenGateService openGateService;

//    private static final String SERVER_URI = "ws://169.254.195.89:61081/";
    private static final String SERVER_URI = "ws://127.0.0.1:61081/";
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();

    private WebSocketSession serverSession;
    private WebSocketSession clientSession;

    @PostConstruct
    private void connectToServer() {
        WebSocketClient client = new StandardWebSocketClient();
        client.doHandshake(new WebSocketHandler() {
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                serverSession = session;
                log.info("Connected to server: " + SERVER_URI);
            }

            @Override
            protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
                messageQueue.put(message.getPayload());
                checkMessages();
            }

            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
                log.info("Disconnected from server: {}", status);
                // 自动重连
                Thread.sleep(5000);
                connectToServer();
            }
        }, SERVER_URI);

    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        this.clientSession = session;
        log.info("Client connected");
    }

/*    @Scheduled(fixedRate = 5000)
    public void printTime() {
        System.out.println("当前时间: " + LocalDateTime.now());
    }*/

    public void checkMessages() {
        while (!messageQueue.isEmpty()) {
            try {
                String message = messageQueue.take();
                processMessage(message);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void processMessage(String message) {
        try {
            //由于Java的泛型类型擦除机制，直接使用.class无法获取完整的泛型信息。
            // Jackson提供了TypeReference类用于捕获泛型类型，从而实现对复杂泛型结构的反序列化。
            // 使用TypeReference是处理此类问题的标准做法。
            List<WebSocketResult> response = objectMapper.readValue(message,
                    new TypeReference<List<WebSocketResult>>() {});
            if (response.get(0).getRefreshTime() != null) {   //存在刷新时间字段
                // 处理门状态信息
                log.info("定时推送的消息（默认30秒周期） 门状态");
                try {
                    log.info((new ObjectMapper()).readTree(message).toPrettyString());
                } catch (JsonProcessingException e) {
                    log.info(message);
                }
                
                for (int i=0; i < response.size(); i++) {
                    WebSocketResult record = response.get(i);
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date refreshTime = sdf.parse(record.getRefreshTime());
                    Date currentTime = new Date();
                    
                    if (response.get(i).getServerTime() != null) {
                        currentTime = sdf.parse(record.getServerTime());
                    }
                    
                    int controllerSN = record.getSn();
                    if (Math.abs(refreshTime.getTime() - currentTime.getTime()) > 60000) {
                        log.info(String.format("控制器SN = %d 通信异常????", controllerSN));
                    }
                }
            } else {
                // 处理透传二维码信息
                try {
                    log.info((new ObjectMapper()).readTree(message).toPrettyString());
                } catch (JsonProcessingException e) {
                    log.info(message);
                }
                for (WebSocketResult record : response) {
                    // 添加检查原始十六进制数据的方法
                    if (record.getOriginalHexData() != null) {
                        // 调用二维码核验接口获取预约记录
                        ZhgjResponse qrCodeResult = zhgjApi.checkByQrCode(record.getConvertToString());
                        // 判断二维码核验结果
                        zhgjApi.judgeStatus(qrCodeResult);
                        // 获取预约记录及其id
                        Map<String, Object> visit = (Map<String, Object>) qrCodeResult.getData();
                        String id = (String) visit.get("id");
                        //调用到访确认接口
                        ZhgjResponse visitResult = zhgjApi.checkVisit(id);
                        //判断到访确认结果
                        if(zhgjApi.judgeStatus(visitResult) == true) {
                            //判断到访状态1和0
                            Map<String, Object> visitStatus = (Map<String, Object>) visitResult.getData();
                            if ("1".equals(visitStatus.get("state"))) {
                                // 到访确认成功，调用闸机接口进行开门
                                sendOpenDoorCommand(
                                        record.getSn(),
                                        record.getGateId()
                                );
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendOpenDoorCommand(int sn, int gateNo) {
        if (serverSession != null && serverSession.isOpen()) {
            openGateService.openGate(sn, gateNo);
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        if (session == clientSession) {
            clientSession = null;
        }
        log.info("Client disconnected: {}", status);
    }
}